#include "parafluidvector.h"

#include <cmath>
#include <limits>

using namespace ParaFluid;

Vector::~Vector()
{
	/* does nothing */
}

Vector::Vector()
	: x(0)
	, y(0)
	, z(0)
{
	/* does nothing */
}

Vector::Vector(float X, float Y, float Z)
	: x(X)
	, y(Y)
	, z(Z)
{
	/* does nothing */
}

Vector::Vector(const Vector & other)
	: x(other.x)
	, y(other.y)
	, z(other.z)
{
	/* does nothing */
}

Vector & Vector::operator= (const Vector & rhs)
{
	if(&rhs != this)
	{
		x = rhs.x;
		y = rhs.y;
		z = rhs.z;
	}
	return *this;
}

bool Vector::operator== (const Vector & rhs) const
{
	bool result = true;
	if(&rhs != this)
	{
		result = (x == rhs.x) && (y == rhs.y) && (z == rhs.z);
	}
	return result;
}

Vector Vector::operator+ (const Vector & rhs) const
{
	return Vector(x + rhs.x, y + rhs.y, z + rhs.z);
}

Vector & Vector::operator+= (const Vector & rhs)
{
	x += rhs.x;
	y += rhs.y;
	z += rhs.z;
	return *this;
}

Vector Vector::operator- (const Vector & rhs) const
{
	return Vector(x - rhs.x, y - rhs.y, z - rhs.z);
}

Vector & Vector::operator-= (const Vector & rhs)
{
	x -= rhs.x;
	y -= rhs.y;
	z -= rhs.z;
	return *this;
}

Vector Vector::operator* (const float & rhs) const
{
	return Vector(x * rhs, y * rhs, z * rhs);
}

Vector & Vector::operator*= (const float & rhs)
{
	x *= rhs;
	y *= rhs;
	z *= rhs;
	return *this;
}

float Vector::operator* (const Vector & rhs) const
{
	return x * rhs.x + y * rhs.y + z * rhs.z;
}

Vector Vector::operator^ (const Vector & rhs) const
{
	return Vector((y * rhs.z) - (z * rhs.y), -1 * (rhs.z * x) + (rhs.x * z), (x * rhs.y) - (y * rhs.x));
}

Vector & Vector::operator^= (const Vector & rhs)
{
	*this = *this ^ rhs;
	return *this;
}

float Vector::length() const
{
	return sqrt((x * x) + (y * y) + (z * z));
}

void Vector::unitary()
{
	float len = 1.0 / sqrt((double(x) * double(x)) + (double(y) * double(y)) + (double(z) * double(z)));
	if(len == 0 || len == std::numeric_limits<float>::infinity() || len == -1 * std::numeric_limits<float>::infinity() || len != len)
	{
		x = 0;
		y = 0;
		z = 0;
	}
	else
	{
		x *= len;
		y *= len;
		z *= len;
	}
}

float Vector::distanceTo(const Vector & other) const
{
	float dx = x - other.x;
	float dy = y - other.y;
	float dz = z - other.z;
	return sqrt(dx * dx + dy * dy + dz * dz);
}

QDataStream & operator<< (QDataStream & stream, const ParaFluid::Vector & vector)
{
	stream << vector.x;
	stream << vector.y;
	stream << vector.z;
	return stream;	
}
	
QDataStream & operator>> (QDataStream & stream, ParaFluid::Vector & vector)
{
	stream >> vector.x;
	stream >> vector.y;
	stream >> vector.z;
	return stream;
}
